package com.zjy.portdemo.modbus;

import android.content.Context;
import android.util.Log;

import com.app.lxx.pregnancyberth.widge.MyToast;
import com.blankj.utilcode.util.ToastUtils;
import com.zjy.portdemo.util.ByteUtil;
import com.zjy.portdemo.util.CRC_16;
import com.zjy.portdemo.util.SerialPort;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Timer;
import java.util.TimerTask;

public class ModbusMaster extends Thread {

    private ArrayList<Byte> rxTemp = new ArrayList<Byte>();
    private Timer timer10ms = new Timer();

    private String uartPath = "/dev/ttyS1";
    private int baudrate = 9600;
    private final int SLAV_ADD = 1;


    private OutputStream mOutputStream = null;
    private InputStream mInputStream = null;
    private SerialPort mserialPort = null;

    int[] regHodingBuf = new int[256];
    int[] receiveBuff = new int[256];


    /**
     * 需要写到下位机的数据
     */
    public int wuYingDeng_relayOut;         //继电器输出
    public int guanPianDeng_relayOut;
    public int shuZhongDeng_relayOut;
    public int xiaoDu_relayOut;
    public int beiYong_relayOut;
    public int fengmingqi_relayOut;

    public int zhaoMing1_valueOut;          //0-10V输出
    public int zhaoMing2_valueOut;
    public int zhaoMing3_valueOut;          //pwm输出
    public int zhaoMing4_valueOut;
    public int zhaoMing5_valueOut;
    public int zhaoMing6_valueOut;


    /**
     * 需要从下位机读取的数据
     */
    public int geLiDianYuan_switchIn;       //开关量输入
    public int huoZaiBaoJing_switchIn;
    public int beiYong1_switchIn;
    public int beiYong2_switchIn;

    public int wenDu_valueIn;               //0-10V输入
    public int shiDu_valueIn;
    public int yaCha_valueIn;
    public int beiYong_valueIn;

    public int yaQi_valueIn;                //4-20mA输入
    public int danQi_valueIn;
    public int fuYa_valueIn;
    public int erYangHuaTan_valueIn;
    public int xiaoQi_valueIn;
    public int yaSuo_valueIn;
    public int yangQi_valueIn;

    public ModbusMaster(Context context, String uartPath, int baudrate) {
        if (uartPath != null && !"".equals(uartPath) && uartPath.length() > 0)
            this.uartPath = uartPath;
        if (baudrate > 0)
            this.baudrate = baudrate;
        try {
            mserialPort = getSerialPort();
            mInputStream = mserialPort.getInputStream();
            mOutputStream = mserialPort.getOutputStream();
        } catch (InvalidParameterException e) {
            Log.i("sssssss串口打开失败1", e.getMessage());
            e.printStackTrace();
        } catch (SecurityException e) {
            Log.i("sssssss串口打开失败2", e.getMessage());
            e.printStackTrace();
        } catch (IOException e) {
            //Toast.makeText(context,"打开串口失败，请检查硬件连接",Toast.LENGTH_SHORT).show();
            Log.i("sssssss串口打开失败3", e.getMessage());
            e.printStackTrace();
            //return;
        }

    }

    public void sendDataMaster03(byte startAdd, byte num) {

        byte[] txBuf = new byte[16];
        CRC_16 crc = new CRC_16();
        txBuf[0] = SLAV_ADD;
        txBuf[1] = 0x03;
        txBuf[2] = 0x00;
        txBuf[3] = startAdd;
        txBuf[4] = 0x00;
        txBuf[5] = num;
        crc.update(txBuf, 6);
        int temp = crc.getValue();
        txBuf[6] = (byte) (temp >> 8);
        txBuf[7] = (byte) (temp & 0xff);
        onDataSend(txBuf, 8);
    }

    public void sendDataMaster16(byte startAdd, byte num) {
        int i, txCount;
        byte[] txBuf = new byte[256];
        CRC_16 crc = new CRC_16();

        slav_hand_10();

        txBuf[0] = SLAV_ADD; //从机地址
        txBuf[1] = 0x10;     //功能码
        txBuf[2] = 0x00;         //从哪个寄存器开始写
        txBuf[3] = startAdd;     //从哪个寄存器开始写
        txBuf[4] = 0x00;         //写几个寄存器
        txBuf[5] = num;          //写几个寄存器
        txBuf[6] = (byte) (num * 2);         //写几个字节（字节=寄存器*2）
        for (i = 0; i < txBuf[5]; i++) {     //写入的数据
            txBuf[7 + 2 * i] = (byte) (regHodingBuf[i + txBuf[3]] >> 8);
            txBuf[8 + 2 * i] = (byte) (regHodingBuf[i + txBuf[3]] & 0xff);
        }
        crc.update(txBuf, txBuf[6] + 7);
        int temp = crc.getValue();
        txBuf[7 + txBuf[6]] = (byte) ((temp >> 8) & 0xff);//校验码
        txBuf[8 + txBuf[6]] = (byte) (temp & 0xff);//校验码
        txCount = 9 + txBuf[6];
        onDataSend(txBuf, txCount);
    }

    /**
     * @param slav_add 从机地址
     * @param features 功能码（0-255）
     * @param startNum 起始位（0-65535）
     * @param data     数据
     */
    public void sendDataMaster(byte slav_add, byte features, int startNum, int[] data) {
        int i, txCount;
        byte[] txBuf = new byte[256];
        CRC_16 crc = new CRC_16();

        txBuf[0] = slav_add; //从机地址
        txBuf[1] = features;     //功能码
        txBuf[2] = (byte) (startNum >> 8); //从哪个寄存器开始写（高位）
        txBuf[3] = (byte) (startNum & 0xff);  //从哪个寄存器开始写（低位）
        txBuf[4] = (byte) (data.length >> 8);  //写几个寄存器（高位）
        txBuf[5] = (byte) (data.length & 0xff);   //写几个寄存器（低位）
        txBuf[6] = (byte) (data.length * 2);         //写几个字节（字节=寄存器*2）
        for (i = 0; i < data.length; i++) {     //写入的数据
            txBuf[7 + 2 * i] = (byte) (data[i] >> 8);
            txBuf[8 + 2 * i] = (byte) (data[i] & 0xff);
        }
        crc.update(txBuf, txBuf[6] + 7);
        int temp = crc.getValue();
        txBuf[7 + txBuf[6]] = (byte) ((temp >> 8) & 0xff);//校验码
        txBuf[8 + txBuf[6]] = (byte) (temp & 0xff);//校验码
        txCount = 9 + txBuf[6];
        onDataSend(txBuf, txCount);
    }

    /**
     * 调节灯箱灯光
     *
     * @param r  红色
     * @param g  绿色
     * @param b  蓝色
     * @param cw 冷白
     * @param ww 暖白
     */
    public void sendDataMaster02(byte r, byte g, byte b, byte cw, byte ww) {
        int i, txCount;
        byte[] txBuf = new byte[19];
        CRC_16 crc = new CRC_16();
        txBuf[0] = 0x02;//从机地址
        txBuf[1] = 0x10;//功能码
        txBuf[2] = 0x00;//寄存器开始地址
        txBuf[3] = 0x02;//寄存器开始地址
        txBuf[4] = 0x00;//寄存器数量
        txBuf[5] = 0x05;//寄存器数量
        txBuf[6] = 0x0A;//数据长度
        txBuf[7] = 0x00;//第一位
        txBuf[8] = r;//第一位(R)
        txBuf[9] = 0x00;//第二位
        txBuf[10] = g;//第二位(G)
        txBuf[11] = 0x00;//第三位
        txBuf[12] = b;//第三位(B)
        txBuf[13] = 0x00;//第四位
        txBuf[14] = cw;//第四位(冷光)
        txBuf[15] = 0x00;//第五位
        txBuf[16] = ww;//第五位(暖光)
        crc.update(txBuf, 17);
        int temp = crc.getValue();
        txBuf[17] = (byte) ((temp >> 8) & 0xff);//校验码
        txBuf[18] = (byte) (temp & 0xff);//校验码
        onDataSend(txBuf, 19);
        Log.i("ssssss", "灯箱更新");
    }

    /**
     * 调节灯箱灯光
     *
     * @param r  红色
     * @param g  绿色
     * @param b  蓝色
     * @param cw 冷白
     * @param ww 暖白
     */
    public void sendDataMaster02_1(byte r, byte g, byte b, byte cw, byte ww) {
        int i, txCount;
        byte[] txBuf = new byte[29];
        CRC_16 crc = new CRC_16();
        txBuf[0] = 0x02;//从机地址
        txBuf[1] = 0x10;//功能码
        txBuf[2] = 0x00;//寄存器开始地址
        txBuf[3] = 0x00;//寄存器开始地址
        txBuf[4] = 0x00;//寄存器数量
        txBuf[5] = 0x0A;//寄存器数量
        txBuf[6] = 0x14;//数据长度
        txBuf[7] = 0x00;
        txBuf[8] = 0x00;
        txBuf[9] = 0x00;
        txBuf[10] = 0x00;
        txBuf[11] = 0x00;//第一位
        txBuf[12] = r;//第一位(R)
        txBuf[13] = 0x00;//第二位
        txBuf[14] = g;//第二位(G)
        txBuf[15] = 0x00;//第三位
        txBuf[16] = b;//第三位(B)
        txBuf[17] = 0x00;//第四位
        txBuf[18] = cw;//第四位(冷光)
        txBuf[19] = 0x00;//第五位
        txBuf[20] = ww;//第五位(暖光)
        txBuf[21] = 0x00;
        txBuf[22] = 0x00;
        txBuf[23] = 0x00;
        txBuf[24] = 0x00;
        txBuf[25] = 0x00;
        txBuf[26] = 0x00;
        crc.update(txBuf, 27);
        int temp = crc.getValue();
        txBuf[27] = (byte) ((temp >> 8) & 0xff);//校验码
        txBuf[28] = (byte) (temp & 0xff);//校验码
        onDataSend(txBuf, 29);
        Log.i("ssssss", "灯箱更新");
    }


    public void closePort() throws IOException {
        mInputStream.close();
        mOutputStream.close();
    }

    /**
     * 数据等待接收
     */
    public void run() {
        super.run();
        timer10ms.schedule(taskPoll, 10, 10);//10ms后开始，每10ms轮询一次
        while (!isInterrupted()) {

            int size;
            try {
                byte[] reBuf = new byte[128];
                if (mInputStream == null)
                    return;
                size = mInputStream.read(reBuf);
                if (size > 0) {
                    for (int i = 0; i < size; i++) {
                        rxTemp.add((reBuf[i]));
                    }
                }
                Log.i("sssssss数据接收", CRC_16.getBufHexStr(reBuf));
            } catch (Exception e) {
                e.printStackTrace();
                try {
                    mInputStream.close();
                    mInputStream.close();
                } catch (Exception e1) {
                    e1.printStackTrace();
                }
            }
        }
    }

    /**
     * 判断接收空闲，总线空闲时置位rxFlag
     */
    private TimerTask taskPoll = new TimerTask() {
        int txDataLengthTemp = 0;
        int txIdleCount = 0;

        public void run() {

            if (rxTemp.size() > 0) {
                if (txDataLengthTemp != rxTemp.size()) {
                    txDataLengthTemp = rxTemp.size();
                    txIdleCount = 0;
                }
                if (txIdleCount < 4) {
                    txIdleCount++;
                    if (txIdleCount >= 4) {
                        txIdleCount = 0;

                        try {

                            byte[] rxTempByteArray = new byte[rxTemp.size() + 255];
                            int i = 0;
                            Iterator<Byte> iterator = rxTemp.iterator();
                            while (iterator.hasNext()) {

                                if (i < rxTemp.size() + 255) {
                                    rxTempByteArray[i] = iterator.next();
                                    i++;
                                }
                            }
                            onDataReceived(rxTempByteArray, rxTemp.size());
                            rxTemp.clear();

                        } catch (Exception e) {
                            rxTemp.clear();
                            e.printStackTrace();
                        }
                    }
                }
            } else {
                txDataLengthTemp = 0;
            }
        }
    };


    /***********************************************  *********************************************/

    /***
     *
     * @return mserialPort_1
     * @throws IOException
     * @throws InvalidParameterException
     */
    public SerialPort getSerialPort() throws SecurityException, IOException, InvalidParameterException {
        if (mserialPort == null) {
            String path = uartPath;
            if ((path.length() == 0) || (baudrate == -1)) {
                throw new InvalidParameterException();
            }
            mserialPort = new SerialPort(new File(path), baudrate, 0);

        }
        return mserialPort;
    }

    /**
     * 收到数据
     *
     * @param reBuf
     * @param size
     */
    private void onDataReceived(byte[] reBuf, int size) {

        if (!(SLAV_ADD == reBuf[0])) {
            return;
        }
        if (size <= 3)
            return;
        if (CRC_16.checkBuf(reBuf)) {//收到的数据效验CRC16是否正确
            if (0x03 == reBuf[1]) {
                mod_Fun_03_Slav(reBuf, size);
            }
        }
    }

    /**
     * 串口发送方法
     *
     * @param seBuf
     * @param size
     */
    public void onDataSend(byte[] seBuf, int size) {
        try {
            mOutputStream = mserialPort.getOutputStream();
            mOutputStream.write(seBuf, 0, size);

            byte[] newArray;
            newArray = Arrays.copyOfRange(seBuf, 0, size);
            Log.i("ssssss串口发送成功：", ByteUtil.toHexString(newArray));
        } catch (Exception e) {
            Log.i("ssssssc串口发送异常", e.getMessage() + "");
        }
    }


    private void slav_hand_10() {


        if (1 == beiYong_relayOut) {

            regHodingBuf[16] |= 1 << 0;
        } else {
            regHodingBuf[16] &= ~(1 << 0);
        }

        if (1 == xiaoDu_relayOut) {

            regHodingBuf[16] |= 1 << 1;
        } else {
            regHodingBuf[16] &= ~(1 << 1);
        }

        if (1 == shuZhongDeng_relayOut) {

            regHodingBuf[16] |= 1 << 2;
        } else {
            regHodingBuf[16] &= ~(1 << 2);
        }

        if (1 == guanPianDeng_relayOut) {

            regHodingBuf[16] |= 1 << 3;
        } else {
            regHodingBuf[16] &= ~(1 << 3);
        }

        if (1 == wuYingDeng_relayOut) {

            regHodingBuf[16] |= 1 << 4;
        } else {
            regHodingBuf[16] &= ~(1 << 4);
        }
        if (1 == fengmingqi_relayOut) {

            regHodingBuf[16] |= 1 << 5;
        } else {
            regHodingBuf[16] &= ~(1 << 5);
        }
        if (1 == fengmingqi_relayOut) {

            regHodingBuf[16] |= 1 << 6;
        } else {
            regHodingBuf[16] &= ~(1 << 6);
        }

        regHodingBuf[17] = zhaoMing1_valueOut;
        regHodingBuf[18] = zhaoMing2_valueOut;
        regHodingBuf[19] = zhaoMing3_valueOut;
        regHodingBuf[20] = zhaoMing4_valueOut;
        regHodingBuf[21] = zhaoMing5_valueOut;
        regHodingBuf[22] = zhaoMing6_valueOut;
    }

    private void slav_hand_03() {

        geLiDianYuan_switchIn = (receiveBuff[0] >> 0) & 0x01;
        huoZaiBaoJing_switchIn = (receiveBuff[0] >> 1) & 0x01;
        beiYong1_switchIn = (receiveBuff[0] >> 2) & 0x01;
        beiYong2_switchIn = (receiveBuff[0] >> 3) & 0x01;

        beiYong_valueIn = receiveBuff[1];
        wenDu_valueIn = receiveBuff[2];
        shiDu_valueIn = receiveBuff[3];
        yaCha_valueIn = receiveBuff[4];
        yaQi_valueIn = receiveBuff[5];
        danQi_valueIn = receiveBuff[6];
        fuYa_valueIn = receiveBuff[7];
        erYangHuaTan_valueIn = receiveBuff[8];
        xiaoQi_valueIn = receiveBuff[9];
        yaSuo_valueIn = receiveBuff[10];
        yangQi_valueIn = receiveBuff[11];

    }

    private void mod_Fun_03_Slav(byte[] reBuf, int size) {

        byte crch, crcl;

        CRC_16 crc = new CRC_16();

        if (reBuf[0] != SLAV_ADD)
            return;                            //地址相符时，再对本帧数据进行校验
        if (reBuf[1] != 0x03)
            return;                                    //检验功能码
        crc.update(reBuf, size - 2);
        int value = crc.getValue();

        crch = (byte) (value >> 8);
        crcl = (byte) (value & 0xFF);
        if ((reBuf[size - 1] != crcl) || (reBuf[size - 2] != crch)) {
            return;    //如CRC校验不符时直接退出
        }

        for (int i = 0; i < reBuf[2] / 2; i++) {
            int highByte = crc.getUnsignedByte(reBuf[3 + 2 * i]) << 8;
            int lowByte = crc.getUnsignedByte(reBuf[4 + 2 * i]);
            receiveBuff[i] = highByte + lowByte;
        }

        slav_hand_03();
    }

    public void addModbusToEendData(String data) {
        try {
            if (data.length() % 2 == 0) {
                int datalength = data.length();
                int newdatalength = datalength / 2 + 2;
                byte[] sendData = new byte[newdatalength];
                for (int i = 0; i < datalength / 2; i++) {
                    String dd = data.substring(i * 2, i * 2 + 2);
                    int di = Integer.parseInt(dd, 16);
                    sendData[i] = (byte) di;
                }
                CRC_16 crc = new CRC_16();
                crc.update(sendData, newdatalength - 2);
                int temp = crc.getValue();
                sendData[newdatalength - 2] = (byte) (temp >> 8);
                sendData[newdatalength - 1] = (byte) (temp & 0xff);
                onDataSend(sendData, newdatalength);
                Log.e("sssss", "发送成功");
                ToastUtils.showShort("发送成功,地址+命令:" + data);
            } else {
                Log.e("ssss", "出错");
                ToastUtils.showShort("发送出错,地址+命令:" + data);
            }
        } catch (Exception e) {
            e.printStackTrace();
            ToastUtils.showShort("地址+命令:" + data + "\n异常信息:" + e.getMessage());
        }
    }
}